package com.twu.biblioteca.commandexecutor;

import com.twu.biblioteca.commandexecutor.subexecutors.*;
import com.twu.biblioteca.librarycollection.LibraryCollection;
import com.twu.biblioteca.memberdata.MemberData;
import com.twu.biblioteca.memberdata.UserDetails;

import java.util.ArrayList;
import java.util.List;

/*
 * This is the submodule version of the command executor. Instead of using an if/elseif block, it accepts submodules
 * which handle different commands. This makes it easy to add additional commands without changing the execute method,
 * and would even make it possible to add or remove commands dynamically.
 */
public class BibliotecaCommandExecutor_SubModules implements AbstractBibliotecaCommandExecutor {

    List <SubExecutor> subExecutors;
    SubExecutor curSubExecutor = null;

    public static final String unknownCommandMessage = "Unknown Command";
    public static final String helloMessage = "Hello!";
    public static final String byeMessage = "Bye!";
    private String enterNextCommandMessage = "Enter Command (Press 1 to display all menu options): ";

    public static interface SubExecutor
    {
        public String getMenuOptionText();
        public String getMenuOptionDescription();
        public boolean canExecute(String command);
        public String execute(
                LibraryCollection libraryColl, MemberData memberData, UserDetails userDetails, String command)
                throws ProgramExitRequestedException, WrongCommandFormatException;
        public boolean isDone();
        public void reset();
    }

    public BibliotecaCommandExecutor_SubModules(List<SubExecutor> subExecutorList)
    {
        subExecutors = subExecutorList;
    }

    public static BibliotecaCommandExecutor_SubModules createCommandExecutorWithStandardSubExecutors()
    {
        List <SubExecutor> subExecutors = new ArrayList<SubExecutor>();
        subExecutors.add(new DisplayMenuSubExecutor(subExecutors.size()+1));
        subExecutors.add(new LoginSubExecutor(subExecutors.size()+1));
        subExecutors.add(new ListBooksSubExecutor(subExecutors.size()+1));
        subExecutors.add(new ListMoviesSubExecutor(subExecutors.size()+1));
        subExecutors.add(new ReserveBookSubExecutor(subExecutors.size()+1));
        subExecutors.add(new GetMemberDetailsSubExecutor(subExecutors.size()+1));
        subExecutors.add(new LogoutSubExecutor(subExecutors.size()+1));

        return new BibliotecaCommandExecutor_SubModules(subExecutors);
    }

    public String processCommand(LibraryCollection libraryColl, MemberData memberData, UserDetails userDetails, String command) throws ProgramExitRequestedException
    {
        command = command.trim();

        if(curSubExecutor != null && curSubExecutor.isDone())
        {
            curSubExecutor.reset();
            curSubExecutor = null;
        }

        if(curSubExecutor == null)
        {
            for(SubExecutor subExecutor : subExecutors)
            {
                if(subExecutor.canExecute(command))
                {
                    curSubExecutor = subExecutor;
                }
            }
        }

        if(curSubExecutor == null)
        {
            return unknownCommandMessage;
        }

        try
        {
            String returnStr = curSubExecutor.execute(libraryColl, memberData, userDetails, command);
            if(curSubExecutor.isDone())
            {
                curSubExecutor.reset();
                curSubExecutor = null;
                returnStr += this.getEnterNextCommandMessage();
            }

            return returnStr;
        }
        catch(WrongCommandFormatException wcfException)
        {
            curSubExecutor.reset();
            curSubExecutor = null;
            return wcfException.getWrongFormatMsg();
        }

    }

    public String getHelloMessage()
    {
        return helloMessage;
    }

    public String getByeMessage()
    {
        return byeMessage;
    }

    public String getEnterNextCommandMessage()
    {
        return enterNextCommandMessage;
    }

    public String getMenu()
    {
        String menu = "";
        for(SubExecutor subExecutor : subExecutors)
        {
            menu += "(" + subExecutor.getMenuOptionText() + ") " + subExecutor.getMenuOptionDescription() + "\n";
        }
        return menu;
    }

    public static String getStandardMenu()
    {
        return BibliotecaCommandExecutor_SubModules.createCommandExecutorWithStandardSubExecutors().getMenu();
    }
}
